/*
点分树就是每次点分治将重心与其余连通块的重心连接起来构建的树，将该树构建出来，存储需要的信息，可以很快处理一些询问

对于一次分治，如果询问点在重心上，则可以直接处理，否则需要点分治：递归+归并，归并包含其他子树上满足要求的点，答案分为两部分，一部分为询问点到重心的距离，另一部分为其他子树上满足要求的点到重心的距离，这部分可以通过预处理前缀和求得
*/
#define quickread
#ifdef quickread
#include <cstdio> 
template <typename T>
inline void read(T& x)
{
    int c=getchar(), f=1; x=0;
    while(c<'0'||'9'<c) {if(c=='-') f=-1; c=getchar();}
    while('0'<=c&&c<='9') 
        x=(x<<3)+(x<<1)+c-'0', c=getchar();
    x*=f;
}
template <typename T>
inline void quickwrite(T x)
{
    if(x<0) putchar('-'), x*=-1;
    if(x>=10) quickwrite(x/10);
    putchar(x%10+'0');
}
#else 
#include <iostream>
#endif
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define DEBUG
using ll=long long;
const int N=1.5e5+10, M=N<<1;
int h[N], w[M], e[M], ne[M], idx;

int n, m, A;
int age[N]; //每个节点处妖怪的年龄
bool st[N];
struct Father //节点到重心的信息
{
    int u, num; //当前节点编号 所在子树编号
    ll dist;
};

vector<Father> father[N]; //每个节点到不同重心的信息
struct Son //子节点的妖怪年龄和到当前节点的距离
{
    int age;
    ll dist;
    bool operator< (const Son& t) const
    {
        return age < t.age;
    }
};
vector<Son> son[N][3]; //存储每个重心不同方向子节点的相关信息
// 这个树所有顶点的度数都小于或等于3

// 添加一条边a->b
void AddEdge(int a, int b, int c)
{
    e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++; 
}

int GetSize(int u, int fa) //求子树大小
{
    if(st[u]) return 0;
    int res=1; //u的大小
    for(int i=h[u]; ~i; i=ne[i])
        if(e[i]!=fa)
            res+=GetSize(e[i], u);
    return res;
}

int GetWC(int u, int fa, int tot, int& wc) //求u为根节点的子树的重心wc
{
    if(st[u]) return 0;
    int sum=1, ms=0;//累加子树大小 最大子树大小
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        int t=GetWC(v, u, tot, wc); //子树重心，t为子树大小
        ms=max(ms, t); //更新最大子树
        sum+=t; //总节点个数
    }
    ms=max(ms, tot-sum); //u此时为根节点，任意一方向均为其子树，降低时间复杂度
    if(ms<=(tot>>1)) wc=u; //u为根节点的子树大小超过总结点的一半，则为重心
    return sum;
}

void GetDist(int u, int fa, ll dist, int wc, int k, vector<Son>& p)
{
    if(st[u]) return; //当前路径长度超过，剪枝
    father[u].push_back({wc, k, dist});
    p.push_back({age[u], dist});
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        GetDist(v, u, dist+w[i], wc, k, p);
    }
}

void calc(int u) //分治计算函数 处理u所在的树
{
    if(st[u]) return; //u已被删除
    GetWC(u, -1, GetSize(u, -1), u); //得到u为根节点的子树的重心，并变为根节点
    st[u]=true; //u当作重心已被处理

    // 归并
    for(int i=h[u], k=0; ~i; i=ne[i])
    {
        int v=e[i];
        if(st[v]) continue;
        auto& p=son[u][k]; //当前节点的第k个孩子
        p.push_back({-1, 0}), p.push_back({A+1, 0}); //哨兵
        GetDist(v, -1, w[i], u, k, p);
        k++;
        sort(p.begin(), p.end());

        for(int i=1; i<p.size(); i++) 
            p[i].dist+=p[i-1].dist; //前缀和处理
        
    }
    for(int i=h[u]; ~i; i=ne[i]) calc(e[i]);
}

ll query(int u, int l, int r)
{
    ll res=0;
    for(auto &t:father[u])
    {
        int g=age[t.u];
        if(l<=g&&g<=r) res+=t.dist; //当前点本身就符合
        for(int i=0; i<3; i++)
        {
            if(i==t.num) continue; //处理其他子树
            auto &p=son[t.u][i];
            if(p.empty()) continue;

            //p此时拿到所有符合条件点的信息
            int a=lower_bound(p.begin(), p.end(), Son({l, -1}))-p.begin();
            int b=lower_bound(p.begin(), p.end(), Son({r+1, -1}))-p.begin();
            res+=t.dist*(b-a)+p[b-1].dist-p[a-1].dist; //前缀和
        }
    }
        
    for(int i=0; i<3; i++) //计算当前子树
    {
        auto &p=son[u][i];
        if(p.empty()) continue;

        //p此时拿到所有符合条件点的信息
        int a=lower_bound(p.begin(), p.end(), Son({l, -1}))-p.begin();
        int b=lower_bound(p.begin(), p.end(), Son({r+1, -1}))-p.begin();
        res+=p[b-1].dist-p[a-1].dist; //前缀和
    }
    return res;
}

void init()
{
    read(n), read(m), read(A);
    for(int i=1; i<=n; i++) read(age[i]);
    memset(h, -1, sizeof h);
    for(int i=0; i<n-1; i++)
    {
        int a, b, c; read(a), read(b), read(c);
        AddEdge(a, b, c); AddEdge(b, a, c);
    }
}

void solve()
{
    init();
    calc(1);
    ll res=0;
    while(m--)
    {
        int u, a, b;
        read(u), read(a), read(b);
        int l=(a+res)%A, r=(b+res)%A;
        // printf("query(%d %d %d)\n", u, l, r);
        if(l>r) swap(l, r);
        res=query(u, l, r);
        quickwrite(res), puts("");
    }
}

// #undef DEBUG
signed main()
{
    #ifdef DEBUG
        freopen("./in.txt", "r", stdin);
        // freopen("./out.txt", "w", stdout);
    #endif
    #ifndef quickread
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    #endif

    int T=1; //scanf("%d", &T);
    while(T--) 
    {
        solve();
    }
    return 0;
}
